﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net.Sockets;
using System.Collections;
using System.Threading;
using System.IO;
using System.Net;
using System.Text.RegularExpressions;
using SocketAPI.ClientTools;

namespace SocketAPI
{
    public class ClientSocketThread
    {
        public Socket handler;
        public Socket listener;
        public int threads;
        public ArrayList dataLines;
        public string data;
        public byte[] bytes;
        public ArrayList clientSocketsRef;
        public int clientIndex = -1;
        public bool Alive = false;
        public string typeString = "NaN";
        //Declare the Events
        public delegate void MessageReceivedHandler(object sender, ClientMessageReceivedArgs ca);

        public event MessageReceivedHandler MessageReceived;

        /// <summary>
        /// Main Constructor
        /// </summary>
        /// <param name="handlerSocket">Main Handler Socket for the Client.</param>
        /// <param name="serverSocket">Main Server Socket for the Client.</param>
        /// <param name="threadsCount">Number of Threads</param>
        /// <param name="dataLinesRef">?</param>
        /// <param name="clientSockets">Referenece to the ClientSockets Array</param>
        /// <param name="srv_password">Password for the Server.</param>
        public ClientSocketThread(Socket handlerSocket, Socket serverSocket, int threadsCount, ArrayList dataLinesRef, ArrayList clientSockets, byte[] srv_password)
        {
            this.clientSocketsRef = clientSockets;
            this.threads = threadsCount;
            this.dataLines = dataLinesRef;
            this.handler = handlerSocket;
            this.listener = serverSocket;
            this.Alive = true;
        }
        /// <summary>
        /// Runs a Function on another thread.
        /// </summary>
        public void runThread()
        {
            //Set ClientIndex int.
            this.clientIndex = this.clientSocketsRef.Count;
            //Write Client Connected
            Console.WriteLine("[" + typeString + "][" + clientIndex + "]" + "Connected!");
            //Asking Client what it is
            ClientHandler.sendMsg(handler, "Client->Priority->WhoAreYou->whoareyou");
            //Add to ActiveClients
            socketAPI.SocketServerConn.activeClients += 1;
            //Start Loop for Receiving Data
            while (true)
            {
                //Create Byte
                bytes = new byte[1024];
                //Create Byte Received Variable.
                int bytesRec = 0;
                try
                {
                    //Wait until Bytes are Sent from client. Then set Bytes to bytes variable.
                    bytesRec = handler.Receive(bytes);
                }
                catch (Exception e)
                {
                    //Write Error (if any).
                    Console.WriteLine(e.Message);
                }
                //Convert Bytes to String.
                data += Encoding.ASCII.GetString(bytes, 0, bytesRec);
                //Process Message and Send to Event Handler.
                //Example Command:
                //Tier1->Tier2->Command->Argument1
                string[] splitData = Regex.Split(data, "\n");
                foreach (string line in splitData)
                {
                    string[] splitCommand = Regex.Split(line, "->");
                    try
                    {
                        if (line != "")
                        {
                            ClientTools.ClientCommandStringParser.parseCommandString(
                                this, //Client Thread (this)
                                handler, //Client Socket
                                listener, //Listener Socket
                                line, //Full Line
                                splitCommand[0],//Tier 1 Group
                                splitCommand[1],//Tier 2 Group
                                splitCommand[2],//Command
                                splitCommand[3]);//Argument
                        }
                    }
                    catch (Exception e)
                    {
                        SpecialConsole.Text.WriteLine("Invalid Command Received: " + line + " @ ERROR: " + e.Message, ConsoleColor.Yellow);
                    }
                }
                data = "";
            }
        }
    }
}
/// <summary>
/// Some Extensions for Sockets.
/// </summary>
public static class SocketExtensions
{
    public static bool IsConnected(this Socket socket)
    {
        try
        {
            return !(socket.Poll(1, SelectMode.SelectRead) && socket.Available == 0);
        }
        catch (SocketException) { return false; }
    }
}
